using System;
using HslCommunication.BasicFramework;

namespace HslCommunication.Profinet.Omron
{
	/// <summary>
	/// Omron PLC的FINS协议相关的辅助类，主要是一些地址解析，读写的指令生成。<br />
	/// The auxiliary classes related to the FINS protocol of Omron PLC are mainly some address resolution and the generation of read and write instructions.
	/// </summary>
	public class OmronFinsNetHelper
	{
		/// <summary>
		/// 解析欧姆龙的数据地址，参考来源是Omron手册第188页，比如D100， E1.100<br />
		/// Analyze Omron's data address, the reference source is page 188 of the Omron manual, such as D100, E1.100
		/// </summary>
		/// <param name="address">数据地址</param>
		/// <param name="isBit">是否是位地址</param>
		/// <returns>解析后的结果地址对象</returns>
		public static OperateResult<OmronFinsDataType, byte[]> AnalysisAddress(string address, bool isBit)
		{
			OperateResult<OmronFinsDataType, byte[]> operateResult = new OperateResult<OmronFinsDataType, byte[]>();
			try
			{
				switch (address[0])
				{
				case 'D':
				case 'd':
					operateResult.Content1 = OmronFinsDataType.DM;
					break;
				case 'C':
				case 'c':
					operateResult.Content1 = OmronFinsDataType.CIO;
					break;
				case 'W':
				case 'w':
					operateResult.Content1 = OmronFinsDataType.WR;
					break;
				case 'H':
				case 'h':
					operateResult.Content1 = OmronFinsDataType.HR;
					break;
				case 'A':
				case 'a':
					operateResult.Content1 = OmronFinsDataType.AR;
					break;
				case 'E':
				case 'e':
				{
					string[] array = address.Split(new char[1]
					{
						'.'
					}, StringSplitOptions.RemoveEmptyEntries);
					int num = Convert.ToInt32(array[0].Substring(1), 16);
					if (num < 16)
					{
						operateResult.Content1 = new OmronFinsDataType((byte)(32 + num), (byte)(160 + num));
					}
					else
					{
						operateResult.Content1 = new OmronFinsDataType((byte)(224 + num - 16), (byte)(96 + num - 16));
					}
					break;
				}
				default:
					throw new Exception(StringResources.Language.NotSupportedDataType);
				}
				if (address[0] == 'E' || address[0] == 'e')
				{
					string[] array2 = address.Split(new char[1]
					{
						'.'
					}, StringSplitOptions.RemoveEmptyEntries);
					if (isBit)
					{
						ushort value = ushort.Parse(array2[1]);
						operateResult.Content2 = new byte[3];
						operateResult.Content2[0] = BitConverter.GetBytes(value)[1];
						operateResult.Content2[1] = BitConverter.GetBytes(value)[0];
						if (array2.Length > 2)
						{
							operateResult.Content2[2] = byte.Parse(array2[2]);
							if (operateResult.Content2[2] > 15)
							{
								throw new Exception(StringResources.Language.OmronAddressMustBeZeroToFifteen);
							}
						}
					}
					else
					{
						ushort value2 = ushort.Parse(array2[1]);
						operateResult.Content2 = new byte[3];
						operateResult.Content2[0] = BitConverter.GetBytes(value2)[1];
						operateResult.Content2[1] = BitConverter.GetBytes(value2)[0];
					}
				}
				else if (isBit)
				{
					string[] array3 = address.Substring(1).Split(new char[1]
					{
						'.'
					}, StringSplitOptions.RemoveEmptyEntries);
					ushort value3 = ushort.Parse(array3[0]);
					operateResult.Content2 = new byte[3];
					operateResult.Content2[0] = BitConverter.GetBytes(value3)[1];
					operateResult.Content2[1] = BitConverter.GetBytes(value3)[0];
					if (array3.Length > 1)
					{
						operateResult.Content2[2] = byte.Parse(array3[1]);
						if (operateResult.Content2[2] > 15)
						{
							throw new Exception(StringResources.Language.OmronAddressMustBeZeroToFifteen);
						}
					}
				}
				else
				{
					ushort value4 = ushort.Parse(address.Substring(1));
					operateResult.Content2 = new byte[3];
					operateResult.Content2[0] = BitConverter.GetBytes(value4)[1];
					operateResult.Content2[1] = BitConverter.GetBytes(value4)[0];
				}
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
			operateResult.IsSuccess = true;
			return operateResult;
		}

		/// <summary>
		/// 根据读取的地址，长度，是否位读取创建Fins协议的核心报文<br />
		/// According to the read address, length, whether to read the core message that creates the Fins protocol
		/// </summary>
		/// <param name="address">地址，具体格式请参照示例说明</param>
		/// <param name="length">读取的数据长度</param>
		/// <param name="isBit">是否使用位读取</param>
		/// <returns>带有成功标识的Fins核心报文</returns>
		public static OperateResult<byte[]> BuildReadCommand(string address, ushort length, bool isBit)
		{
			OperateResult<OmronFinsDataType, byte[]> operateResult = AnalysisAddress(address, isBit);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			byte[] array = new byte[8]
			{
				1,
				1,
				0,
				0,
				0,
				0,
				0,
				0
			};
			if (isBit)
			{
				array[2] = operateResult.Content1.BitCode;
			}
			else
			{
				array[2] = operateResult.Content1.WordCode;
			}
			operateResult.Content2.CopyTo(array, 3);
			array[6] = (byte)((int)length / 256);
			array[7] = (byte)((int)length % 256);
			return OperateResult.CreateSuccessResult(array);
		}

		/// <summary>
		/// 根据写入的地址，数据，是否位写入生成Fins协议的核心报文<br />
		/// According to the written address, data, whether the bit is written to generate the core message of the Fins protocol
		/// </summary>
		/// <param name="address">地址内容，具体格式请参照示例说明</param>
		/// <param name="value">实际的数据</param>
		/// <param name="isBit">是否位数据</param>
		/// <returns>带有成功标识的Fins核心报文</returns>
		public static OperateResult<byte[]> BuildWriteWordCommand(string address, byte[] value, bool isBit)
		{
			OperateResult<OmronFinsDataType, byte[]> operateResult = AnalysisAddress(address, isBit);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			byte[] array = new byte[8 + value.Length];
			array[0] = 1;
			array[1] = 2;
			if (isBit)
			{
				array[2] = operateResult.Content1.BitCode;
			}
			else
			{
				array[2] = operateResult.Content1.WordCode;
			}
			operateResult.Content2.CopyTo(array, 3);
			if (isBit)
			{
				array[6] = (byte)(value.Length / 256);
				array[7] = (byte)(value.Length % 256);
			}
			else
			{
				array[6] = (byte)(value.Length / 2 / 256);
				array[7] = (byte)(value.Length / 2 % 256);
			}
			value.CopyTo(array, 8);
			return OperateResult.CreateSuccessResult(array);
		}

		/// <summary>
		/// 验证欧姆龙的Fins-TCP返回的数据是否正确的数据，如果正确的话，并返回所有的数据内容<br />
		/// Verify that the data returned by Omron's Fins-TCP is correct data, if correct, and return all data content
		/// </summary>
		/// <param name="response">来自欧姆龙返回的数据内容</param>
		/// <param name="isRead">是否读取</param>
		/// <returns>带有是否成功的结果对象</returns>
		public static OperateResult<byte[]> ResponseValidAnalysis(byte[] response, bool isRead)
		{
			if (response.Length >= 16)
			{
				int num = BitConverter.ToInt32(new byte[4]
				{
					response[15],
					response[14],
					response[13],
					response[12]
				}, 0);
				if (num > 0)
				{
					return new OperateResult<byte[]>(num, GetStatusDescription(num));
				}
				byte[] array = new byte[response.Length - 16];
				Array.Copy(response, 16, array, 0, array.Length);
				return UdpResponseValidAnalysis(array, isRead);
			}
			return new OperateResult<byte[]>(StringResources.Language.OmronReceiveDataError);
		}

		/// <summary>
		/// 验证欧姆龙的Fins-Udp返回的数据是否正确的数据，如果正确的话，并返回所有的数据内容<br />
		/// Verify that the data returned by Omron's Fins-Udp is correct data, if correct, and return all data content
		/// </summary>
		/// <param name="response">来自欧姆龙返回的数据内容</param>
		/// <param name="isRead">是否读取</param>
		/// <returns>带有是否成功的结果对象</returns>
		public static OperateResult<byte[]> UdpResponseValidAnalysis(byte[] response, bool isRead)
		{
			if (response.Length >= 14)
			{
				int num = response[12] * 256 + response[13];
				if (!isRead)
				{
					OperateResult<byte[]> operateResult = OperateResult.CreateSuccessResult(new byte[0]);
					operateResult.ErrorCode = num;
					operateResult.Message = GetStatusDescription(num) + " Received:" + SoftBasic.ByteToHexString(response, ' ');
					return operateResult;
				}
				byte[] array = new byte[response.Length - 14];
				if (array.Length != 0)
				{
					Array.Copy(response, 14, array, 0, array.Length);
				}
				OperateResult<byte[]> operateResult2 = OperateResult.CreateSuccessResult(array);
				if (array.Length == 0)
				{
					operateResult2.IsSuccess = false;
				}
				operateResult2.ErrorCode = num;
				operateResult2.Message = GetStatusDescription(num) + " Received:" + SoftBasic.ByteToHexString(response, ' ');
				return operateResult2;
			}
			return new OperateResult<byte[]>(StringResources.Language.OmronReceiveDataError);
		}

		/// <summary>
		/// 根据欧姆龙返回的错误码，获取错误信息的字符串描述文本<br />
		/// According to the error code returned by Omron, get the string description text of the error message
		/// </summary>
		/// <param name="err">错误码</param>
		/// <returns>文本描述</returns>
		public static string GetStatusDescription(int err)
		{
			return err switch
			{
				0 => StringResources.Language.OmronStatus0, 
				1 => StringResources.Language.OmronStatus1, 
				2 => StringResources.Language.OmronStatus2, 
				3 => StringResources.Language.OmronStatus3, 
				20 => StringResources.Language.OmronStatus20, 
				21 => StringResources.Language.OmronStatus21, 
				22 => StringResources.Language.OmronStatus22, 
				23 => StringResources.Language.OmronStatus23, 
				24 => StringResources.Language.OmronStatus24, 
				25 => StringResources.Language.OmronStatus25, 
				_ => StringResources.Language.UnknownError, 
			};
		}
	}
}
